package com.wang.jmonkey.interceptor;

import cn.hutool.core.util.ObjectUtil;
import com.github.pagehelper.PageHelper;
import com.wang.jmonkey.common.annotation.PageDefinition;
import com.wang.jmonkey.common.model.query.PageQuery;
import com.wang.jmonkey.interceptor.handler.result.ExceptionResultHandlerManager;
import lombok.extern.slf4j.Slf4j;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.context.support.GenericApplicationContext;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * @Description 分页工具拦截器
 * @Author HeJiawang
 * @Date 2021/5/21 13:12
 */
@Slf4j
public class PageInterceptor implements MethodInterceptor {

    private GenericApplicationContext context;

    public PageInterceptor(GenericApplicationContext context) {
        this.context = context;
    }

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {

        try {
            resolverPageParameter(invocation);

            return invocation.proceed();
        } catch (Throwable e) {
            log.error(this.getClass().getName() + "." + Thread.currentThread().getStackTrace()[1].getMethodName(), e);

            ExceptionResultHandlerManager manager = this.context.getBean(ExceptionResultHandlerManager.class);
            return manager.result(invocation.getMethod().getReturnType(), e.getMessage(), manager);
        }
    }

    /**
     * resolverPageParameter
     * @param invocation invocation
     * @throws Exception e
     */
    private void resolverPageParameter (MethodInvocation invocation) throws Exception {
        if (!invocation.getMethod().isAnnotationPresent(PageDefinition.class)) return;

        Object[] arguments = invocation.getArguments();
        if (ObjectUtil.isEmpty(arguments)) return;

        Method method = invocation.getMethod();
        PageDefinition page = method.getAnnotation(PageDefinition.class);

        Object param = arguments[page.position()];
        Object pageNum, pageSize;

        if (Map.class.isAssignableFrom(param.getClass())) {

            pageNum = ((Map<String , Object>)param).get(page.current());
            pageSize = ((Map<String , Object>)param).get(page.pageSize());
        } else if (PageQuery.class.isAssignableFrom(param.getClass())) {

            Field pageNumField = param.getClass().getSuperclass().getDeclaredField(page.current());
            pageNumField.setAccessible(true);
            pageNum = pageNumField.get(param);

            Field pageSizeField = param.getClass().getSuperclass().getDeclaredField(page.pageSize());
            pageSizeField.setAccessible(true);
            pageSize = pageSizeField.get(param);
        }else {

            Field pageNumField = param.getClass().getDeclaredField(page.current());
            pageNumField.setAccessible(true);
            pageNum = pageNumField.get(param);

            Field pageSizeField = param.getClass().getDeclaredField(page.pageSize());
            pageSizeField.setAccessible(true);
            pageSize = pageSizeField.get(param);
        }

        int num = ObjectUtils.isEmpty(pageNum) ? 1 : Integer.valueOf(pageNum.toString());
        int size = ObjectUtils.isEmpty(pageSize)  ? 20 : Integer.valueOf(pageSize.toString());

        PageHelper.startPage(num , size);
    }
}
